package com.dark.sys.service.impl;

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import com.dark.common.repository.hibernate.HibernateDao;
import com.dark.common.utils.BeanUtils;
import com.dark.sys.entity.Resource;
import com.dark.sys.exception.ResourceException;
import com.dark.sys.service.AuthService;
import com.dark.sys.service.ResourceService;
import com.dark.sys.service.RoleResourceService;
import com.dark.sys.web.dto.AuthDto;
import com.dark.sys.web.dto.ResourceDto;

@Service
public class ResourceServiceImpl implements ResourceService{
	
	@Autowired
	private HibernateDao<Resource, Integer> basedaoResource ;
	
	@Autowired
	private AuthService authService ;
	
	@Autowired
	private RoleResourceService roleResourceService ;
	
	@CacheEvict(value="SystemResourceCache", allEntries=true)
	@Override
	public void add(ResourceDto dto) {
		Resource entity = new Resource() ;
		BeanUtils.copyNotNullProperties(dto, entity);
		entity.setWeight(addInitWeitgh(dto.getPid())); 
		
		Resource ret = this.basedaoResource.save(entity); 
		
		if(dto.getInitCrud()) {
			addInitOperations(ret);
		}
	}
	public void addInitOperations(Resource entity) {
		LinkedHashMap<String, String> crudMap = new LinkedHashMap<String, String>() ;
		crudMap.put("create", "新增") ;
		crudMap.put("delete", "删除") ;
		crudMap.put("update", "修改") ;
		crudMap.put("read", "查询") ;
		Set<String> keys = crudMap.keySet() ;
		for (String key : keys) {
			System.out.println(crudMap.get(key));
			Resource crud = new Resource() ;
			crud.setName(crudMap.get(key));
			crud.setIdentity(key);
			
			crud.setMenuId(entity.getMenuId());
			crud.setPid(entity.getId());
			crud.setType(true);
			crud.setParentIds((null==entity.getParentIds()||"".equals(entity.getParentIds())?"":entity.getParentIds()+"/") + entity.getId());
			crud.setParentIdentity((null==entity.getParentIdentity()||"".equals(entity.getParentIdentity())?"":entity.getParentIdentity()+":")+ entity.getIdentity());
			crud.setWeight(addInitWeitgh(entity.getId()));
			
			this.basedaoResource.save(crud) ;
		}
	}
	/**
	 * 初始化排序
	 * @param pid
	 * @return
	 */
	public int addInitWeitgh(Integer pid) {
		String queryString = "select case when max(weight) is null then 1  when max(weight) = 0 then 1 else (max(weight) + 1) end from sys_resource where "+(null==pid?"pid is null": "pid="+pid) ;
		BigInteger findUniqueSQL = (BigInteger) this.basedaoResource.findUniqueColSQL(queryString) ;
		return findUniqueSQL.intValue() ;
	}
	
	@CacheEvict(value="SystemResourceCache", allEntries=true)
	@Override
	public void delete(Integer id) {
		del(id);
	}
	
	private void del(Integer id) {
		String queryChildCount = "select t.id from sys_resource t where t.pid=?" ;
		List<Resource> childs = this.basedaoResource.findListSQL(queryChildCount, new Object[]{id}, Resource.class, false) ;
		if(null != childs && childs.size() > 0) {
			for (Resource resource : childs) {
				del(resource.getId());
			}
		}
		this.basedaoResource.delete(Resource.class, id) ;
	}

	@CacheEvict(value="SystemResourceCache", allEntries=true)
	@Override
	public void update(ResourceDto dto) {
		Resource entity = this.basedaoResource.getEntity(Resource.class, dto.getId());
		if(dto.getPid() == entity.getId()) {
			throw new ResourceException("自己不可以作为子节点") ;
		}
		if(!dto.getParentIds().equals(entity.getParentIds())) {
			updateChildParentIds(dto, dto.getParentIds(), dto.getParentIdentity());
		}
		
		BeanUtils.copyNotNullProperties(dto, entity);
		if(null == dto.getPid() || "".equals(dto.getPid())) {
			entity.setPid(null);
		}
		this.basedaoResource.update(entity);
	}

	/**
	 * 修改子节点的父路径和父权限路径
	 * @param entity
	 * @param dto
	 * @param pids
	 * @param identitys
	 */
	public void updateChildParentIds(ResourceDto dto, String pids, String identitys) {
		String queryChild = "select t.* from sys_resource t where t.pid=?" ;
		List<ResourceDto> childs = this.basedaoResource.findListSQL(queryChild, new Object[]{dto.getId()}, ResourceDto.class, false) ;
		
		if(null != childs && !childs.isEmpty()) {
			for (ResourceDto child : childs) {
				String line = (pids==null||pids.equals("")?"":"/") ;
				String line1 = (identitys==null||identitys.equals("")?"":":") ;
				
				this.basedaoResource.executeSQL("update sys_resource t set "
						+ "t.parentIds='"+(pids +line+ dto.getId())+"', "
						+ "t.parentIdentity='"+(identitys +line1+ dto.getIdentity())+"' "
						+ "where t.id="+child.getId()) ;
				
				updateChildParentIds(child, (pids +line+ dto.getId()), (identitys +line1+ dto.getIdentity())) ;
			}
		}
	}
	
	@Cacheable(value="SystemResourceCache", key="#root.targetClass + \".\"+ #root.methodName + (\"#ResourceId[\"+#id+\"]\")")
	@Override
	public ResourceDto get(Integer id) {
		Resource entity = this.basedaoResource.getEntity(Resource.class, id) ;
		ResourceDto dto = new ResourceDto() ;
		BeanUtils.copyNotNullProperties(entity, dto);
		return dto;
	}
	
	@Cacheable(value="SystemResourceCache", key="#root.targetClass + \".\"+ #root.methodName + (\"[#menuId=\"+#dto.menuId+\"&filterType=\"+#dto.filterType+\"]\")")
	@Override
	public List<ResourceDto> tree(ResourceDto dto) {
		List<ResourceDto> tg = new ArrayList<ResourceDto>() ;
		
		String queryString = "select t.* from sys_resource t where 1=1 " ;
		
		Map<String, Object> alias = new HashMap<String, Object>() ;
		if(null != dto && dto.getId() != null) {
			queryString += " and t.pid=:pid" ;
			alias.put("pid", dto.getId()) ;
		} else if(null != dto.getMenuId()){
			queryString += " and t.pid is null and t.menuId=:menuId" ;
			alias.put("menuId", dto.getMenuId()) ;
		} else {
			queryString += " and t.pid is null" ;
		}
		
		List<ResourceDto> resources = this.basedaoResource.findListSQL(queryString, alias, ResourceDto.class, false) ;
		
		for (ResourceDto resourceDto : resources) {
			tg.add(recursiveResource(resourceDto, dto.getFilterType())) ;
		}
		return tg;
	}
	
	private ResourceDto recursiveResource(ResourceDto dto, boolean type) {
		Map<String, Object> attributes = new HashMap<String, Object>() ;
		attributes.put("href", dto.getHref()) ;
		attributes.put("iniframe", dto.getIniframe()) ;
		
		dto.setText(dto.getName());
		dto.setAttributes(attributes);
		
		StringBuffer queryStringChild = new StringBuffer("SELECT t.* FROM sys_resource t WHERE 1=1 ") ;
		Map<String, Object> alias = new HashMap<String, Object>() ;
		
		queryStringChild.append(" AND t.pid=:pid") ;
		alias.put("pid", dto.getId()) ;
		
		if(type) { //过滤类型为操作的资源
			queryStringChild.append(" AND t.type<>:type") ;
			alias.put("type", type) ;
		}
		
		List<ResourceDto> childs = this.basedaoResource.findListSQL(queryStringChild.toString(), alias, ResourceDto.class, false) ;
		
		if(null != childs && !childs.isEmpty()) {
			List<ResourceDto> children = new ArrayList<ResourceDto>() ;
			for (ResourceDto child : childs) {
				children.add(recursiveResource(child, type)) ;
			}
			dto.setChildren(children);
		}
		return dto;
	}
	
	
	@Override
	public List<ResourceDto> listAll(ResourceDto dto) {
		StringBuffer queryStringChild = new StringBuffer("SELECT t.* FROM sys_resource t WHERE 1=1 ") ;
		Map<String, Object> alias = new HashMap<String, Object>() ;
		
		if(dto.getFilterType()) { //过滤类型为操作的资源
			queryStringChild.append(" AND t.type<>:type") ;
			alias.put("type", dto.getFilterType()) ;
		}
		
		return this.basedaoResource.findListSQL(queryStringChild.toString(), alias, ResourceDto.class, false) ;
	}
	
	//@Cacheable(value="SystemCache", key="#resourceIds")
	@Override
	public List<ResourceDto> getResourceOperations(String resourceIds) {
		StringBuffer queryStringChild = new StringBuffer("SELECT t.* FROM sys_resource t WHERE t.id in(:ids) ") ;
		Map<String, Object> alias = new HashMap<String, Object>() ;
		
		alias.put("ids", resourceIds.split(",")) ;
		
		return this.basedaoResource.findListSQL(queryStringChild.toString(), alias, ResourceDto.class, false) ;
	}
	
	@Override
	public List<Integer> getResourceOperationsIdsByUserId(Integer userId) {
		List<Integer> resource = new ArrayList<Integer>() ;
		
		AuthDto auth = this.authService.getByUserId(userId) ;
		if(null != auth && null != auth.getRoleIds()) {
			Set<Integer> byRoleToResource = this.roleResourceService.getByRoleToResource(auth.getRoleIds()) ;
			
			StringBuffer queryStringChild = new StringBuffer("SELECT t.id FROM sys_resource t WHERE t.id in(:ids) ") ;
			Map<String, Object> alias = new HashMap<String, Object>() ;
			alias.put("ids", byRoleToResource) ;
			
			List<ResourceDto> list = this.basedaoResource.findListSQL(queryStringChild.toString(), alias, ResourceDto.class, false) ;
			for (ResourceDto resourceDto : list) {
				resource.add(resourceDto.getId()) ;
			}
			
			
		}
		return resource;
	}
	

}
